package com.asha;
import android.graphics.PointF;
import android.support.v4.view.MotionEventCompat;
import android.view.MotionEvent;
import static com.asha.ChromeLikeSwipeLayout.dp2px;
/**
* Created by hzqiujiadi on 15/12/22.
* hzqiujiadi ashqalcn@gmail.com
*/
public class TouchManager {
public static final int INVALID_POINTER = -1;
private boolean mBeginDragging;
private int mTopOffset;
private int mTouchSlop;
private float mTouchDownActor;
private int mActivePointerId = INVALID_POINTER;
private PointF mTmpPoint = new PointF();
private ITouchCallback mTouchCallback;
private int mThreshold = dp2px(120);
private static final int sThreshold2 = dp2px(400);
private int mMotionX;
private boolean mInterceptEnabled = true;
public TouchManager(ITouchCallback mTouchHelper) {
this.mTouchCallback = mTouchHelper;
}
private void onSecondaryPointerUp(MotionEvent ev) {
final int pointerIndex = MotionEventCompat.getActionIndex(ev);
final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
setActivePointerId(ev, newPointerIndex);
}
}
private void setActivePointerId(MotionEvent event, int defaultId){
mActivePointerId = MotionEventCompat.getPointerId(event, defaultId);
final float initialDownY = getCurrentMotionEventY(event);
if ( initialDownY == -1 ) return;
if ( mBeginDragging ){
mTouchDownActor = motionY2TouchDown(initialDownY);
}
}
private void resetActivePointerId(){
mActivePointerId = INVALID_POINTER;
}
private float getCurrentMotionEventY(MotionEvent ev) {
final int index = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
if (index < 0) {
return -1;
}
return MotionEventCompat.getY(ev, index);
}
public void setTouchSlop(int touchSlop) {
this.mTouchSlop = touchSlop;
}
public void endDrag(){
mBeginDragging = false;
}
public float calExpandProgress(int currentTop){
return currentTop * 1.0f / mThreshold;
}
public int calTargetTopOffset(int currentTop){
return calTargetTopOffset(currentTop,getTopOffset());
}
public int calTargetTopOffset(int currentTop, int offset){
int target;
if ( currentTop <= sThreshold2 ) {
if ( offset < 0 ){
target = 0 - currentTop;
} else if ( offset < sThreshold2 ) {
target = offset - currentTop;
} else {
target = sThreshold2 - currentTop;
}
} else {
target = sThreshold2 - currentTop;
}
return target;
}
private void setTopOffset(float y) {
mTopOffset = motionY2TopOffset(y);
}
public int getTopOffset() {
return mTopOffset;
}
public boolean isBeginDragging() {
return mBeginDragging;
}
public PointF event2Point(MotionEvent event){
mTmpPoint.set(event.getX(),event.getY());
return mTmpPoint;
}
private float motionY2TouchDown(float y){
float diff;
if ( mTopOffset < 0 ){
diff = 0;
} else if( mTopOffset > mThreshold){
diff = (mTopOffset - mThreshold) / 0.3f / 0.6f + mThreshold / 0.6f;
} else {
diff = mTopOffset / 0.6f;
}
return y - diff;
}
private int motionY2TopOffset(float y){
float original = y - mTouchDownActor;
float basic = original * 0.6f;
if ( basic > mThreshold){
basic = mThreshold + (basic - mThreshold) * 0.3f;
}
return (int) basic;
}
public boolean onFeedInterceptEvent(MotionEvent event){
int action = event.getAction();
switch ( action & MotionEvent.ACTION_MASK ) {
case MotionEvent.ACTION_DOWN:
setActivePointerId(event, 0);
if ( mBeginDragging ){
return true;
}
final float initialDownY = getCurrentMotionEventY(event);
if (initialDownY == -1) return false;
mTouchDownActor = initialDownY;
mBeginDragging = false;
if ( mTouchCallback != null ) mTouchCallback.onActionDown();
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
resetActivePointerId();
break;
case MotionEvent.ACTION_MOVE:
if ( mActivePointerId == TouchManager.INVALID_POINTER) {
//Log.e(TAG, "Got ACTION_MOVE event but don't have an active pointer id.");
return false;
}
final float y = getCurrentMotionEventY(event);
if (y == -1) {
return false;
}
// if diff > mTouchSlop
// let's drag!
if ( mInterceptEnabled && !mBeginDragging && y - mTouchDownActor > mTouchSlop ) {
mBeginDragging = true;
if (mTouchCallback != null) mTouchCallback.onBeginDragging();
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(event);
break;
}
return mBeginDragging;
}
public boolean onFeedTouchEvent(MotionEvent event){
final int action = MotionEventCompat.getActionMasked(event);
int pointerIndex = MotionEventCompat.findPointerIndex(event, mActivePointerId);
if (pointerIndex < 0) {
//Log.e(TAG, "Got ACTION_MOVE event but have an invalid active pointer id.");
return false;
}
final float y = MotionEventCompat.getY(event, pointerIndex);
setTopOffset(y);
boolean isExpanded = mTopOffset >= mThreshold && mBeginDragging;
//first point
switch ( action ) {
case MotionEvent.ACTION_DOWN:
setActivePointerId(event, 0);
break;
case MotionEvent.ACTION_CANCEL:
if ( mTouchCallback != null ) mTouchCallback.onActionCancel(isExpanded);
break;
case MotionEvent.ACTION_UP:
if ( mTouchCallback != null ) mTouchCallback.onActionUp(isExpanded);
resetActivePointerId();
break;
case MotionEvent.ACTION_MOVE:
mMotionX = (int) MotionEventCompat.getX(event,pointerIndex);
if ( mTouchCallback != null ) mTouchCallback.onActionMove(isExpanded, this);
break;
case MotionEvent.ACTION_POINTER_DOWN:
pointerIndex = MotionEventCompat.getActionIndex(event);
if (pointerIndex < 0) {
//Log.e(TAG, "Got ACTION_POINTER_DOWN event but have an invalid action index.");
return false;
}
setActivePointerId(event, pointerIndex);
break;
case MotionEvent.ACTION_POINTER_UP:
onSecondaryPointerUp(event);
break;
}
return true;
}
public int getMotionX() {
return mMotionX;
}
public void setInterceptEnabled(boolean interceptEnabled) {
this.mInterceptEnabled = interceptEnabled;
}
public void setMaxHeight(int maxHeight) {
this.mThreshold = maxHeight;
}
public interface ITouchCallback {
void onActionDown();
void onActionUp(boolean isExpanded);
void onActionCancel(boolean isExpanded);
void onActionMove(boolean isExpanded, TouchManager touchManager);
void onBeginDragging();
}
}